/*
 * @Author: Wangjun
 * @Date: 2021-05-27 14:34:55
 * @LastEditTime: 2022-09-14 18:37:48
 * @LastEditors: Wangjun
 * @Description:
 * @FilePath: \xrengined:\go\src\gitee.com\haodreams\query\table.go
 * hnxr
 */
package query

import (
	"errors"
	"reflect"

	"gitee.com/haodreams/libs/easy"
)

var (
	errNoData   = errors.New("无数据")
	errNoOkData = errors.New("没有符合条件的数据")
)

/**
 * @description: 查找给定值的值
 * @param {reflect.Value} v
 * @param {[]int} index
 * @return {*}
 */
func FieldByIndex(v reflect.Value, index []int) (rv reflect.Value, err error) {
	if len(index) == 1 {
		return v.Field(index[0]), nil
	}

	//	v.mustBe(Struct)
	for i, x := range index {
		if i > 0 {
			if v.Kind() == reflect.Ptr && v.Type().Elem().Kind() == reflect.Struct {
				if v.IsNil() {
					//panic("reflect: indirection through nil pointer to embedded struct")
					err = errors.New("reflect: indirection through nil pointer to embedded struct")
					return
				}
				v = v.Elem()
			}
		}
		v = v.Field(x)
	}
	return v, nil
}

type Table struct {
	key         map[string][]int
	arrayObject interface{}
	parent      interface{} //父级数据用于OR操作
	//err         error       //错误消息
	result interface{} //保存的结果
}

/**
 * @description: 获取记录集
 * @param {*}
 * @return {*}
 */
func (m *Table) Rows() interface{} {
	return m.arrayObject
}

/**
 * @description: 获取父记录集
 * @param {*}
 * @return {*}
 */
func (m *Table) ParentRows() interface{} {
	return m.parent
}

// Result 计算的结果
func (m *Table) Result() interface{} {
	return m.result
}

/**
 * @description: 获取字段名
 * @param {*}
 * @return {*}
 */
func (m *Table) Keys() (keys []string) {
	for key := range m.key {
		keys = append(keys, key)
	}
	return keys
}

// GetError 获取错误
// func (m *Table) GetError() error {
// 	return m.err
// }

// 新建一个查询
func NewTable(objects interface{}) (q *Table, err error) {
	q = new(Table)
	q.arrayObject = objects
	q.parent = objects
	err = q.init()
	if err != nil {
		return nil, err
	}
	return
}

func (m *Table) init() (err error) {
	//关联key的索引
	t := reflect.TypeOf(m.arrayObject)
	if !(t.Kind() == reflect.Slice || t.Kind() == reflect.Array) {
		err = errors.New("参数错误，参数必须是结构体切片或者数组")
		return
	}
	//log.Println(t.Kind(), t.String())
	t = t.Elem()
	m.key = map[string][]int{}
	//log.Println(t.Elem(), t.Kind())
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}

	if t.Kind() != reflect.Struct {
		err = errors.New("数组的内容不是结构体")
		return
	}
	m.initKey("", nil, t)
	//TODO 查找GUID 字段并赋值,GUID 必须是int类型
	return
}

func (m *Table) initKey(prefix string, paths []int, t reflect.Type) {
	if t.Kind() == reflect.Ptr {
		t = t.Elem()
	}
	//log.Println(prefix + t.String())
	for i := 0; i < t.NumField(); i++ {
		newPaths := make([]int, len(paths))
		copy(newPaths, paths)
		newPaths = append(newPaths, i)
		fieldType := t.Field(i)

		typ := fieldType.Type

		if typ.Kind() == reflect.Ptr {
			typ = typ.Elem()
		}

		//log.Println(prefix+fieldType.Name, typ.Kind())

		if fieldType.Anonymous {
			if typ.Kind() == reflect.Struct {
				m.initKey(prefix, newPaths, typ)
			} else {
				m.key[prefix+fieldType.Name] = newPaths
				//log.Println("field", fieldType.Name, typ.Kind())
			}
			continue
		}
		if typ.Kind() == reflect.Struct {
			if fieldType.Name == "" {
				continue
			}
			if fieldType.Name[0] >= 'A' && fieldType.Name[0] <= 'Z' {
				//m.initKey(prefix+fieldType.Name+".", newPaths, field)
				m.initKey(prefix+fieldType.Name+".", newPaths, typ)
			}
			continue
		}

		if fieldType.Name[0] >= 'A' && fieldType.Name[0] <= 'Z' {
			m.key[prefix+fieldType.Name] = newPaths
		}
	}
}

/**
 * @description: 过虑满足条件的数据
 * @param {*Query} m
 * @return {*}
 */
func (m *Table) orFilter(
	key string,
	value interface{},
	intFunc func(a, b int64) bool,
	floatFunc func(a, b float64) bool,
	stringFunc func(a, b string) bool,
) (arr *Table, err error) {
	arr = new(Table)
	arr.key = m.key
	//or 运算，继承父对象
	arr.parent = m.parent

	v := reflect.ValueOf(m.parent)
	n, valueType, ids, err := m.checkPreconditionsOr(v, key)
	if err != nil {
		if !(err == errNoData || err == errNoOkData) {
			return
		}
	}
	floatValue := 0.0
	intValue := int64(0)
	stringValue := ""
	mp := m.add2Map()

	//如果值类型是数字，则参数类型必须是数字
	if valueType != easy.TypeString {
		paramType := easy.GetType(value)
		if paramType == easy.TypeNull || paramType == easy.TypeString {
			err = errors.New("参数类型和值类型不一致")
			return
		}
	}

	switch valueType {
	case easy.TypeFloat:
		floatValue, _ = easy.GetFloat64(value)
	case easy.TypeInt:
		intValue, _ = easy.GetInt64(value)
	case easy.TypeString:
		stringValue = value.(string)
	default:
		err = errors.New("不支持的数据类型")
		return
	}

	for i := 0; i < n; i++ {
		field := v.Index(i)
		if field.Kind() == reflect.Ptr {
			if field.IsNil() {
				continue
			}
		}
		addr := field.Pointer()
		elem := reflect.Indirect(field)
		if elem.IsValid() && !elem.CanInterface() {
			continue
		}
		//ie := elem.Interface()
		//log.Println(ie)
		if !elem.IsValid() {
			continue
		}
		elem, err = FieldByIndex(elem, ids)
		if err != nil {
			continue
		}
		if !elem.CanInterface() {
			continue
		}
		switch valueType {
		case easy.TypeFloat:
			fval, err := easy.GetFloat64(elem.Interface())
			if err != nil {
				continue
			}
			if floatFunc(fval, floatValue) {
				if _, ok := mp[addr]; !ok {
					mp[addr] = field
				}
			} else {
				continue
			}
		case easy.TypeInt:
			ival, err := easy.GetInt64(elem.Interface())
			if err != nil {
				continue
			}
			if intFunc(ival, intValue) {
				if _, ok := mp[addr]; !ok {
					mp[addr] = field
				}
			} else {
				continue
			}
		case easy.TypeString:
			if stringFunc(elem.String(), stringValue) {
				if _, ok := mp[addr]; !ok {
					mp[addr] = field
				}
			} else {
				continue
			}
		default:
			continue
		}
	}

	if len(mp) == 0 {
		err = errNoOkData
	} else {
		vals := reflect.MakeSlice(v.Type(), len(mp), n)
		count := 0
		for _, val := range mp {
			vals.Index(count).Set(val)
			count++
		}
		arr.arrayObject = vals.Interface()
		err = nil
	}
	return
}

/**
 * @description: row (*struct) 加入到map
 * @param {*}
 * @return {*}key=struct 地址
 */
func (m *Table) add2Map() (mp map[uintptr]reflect.Value) {
	mp = map[uintptr]reflect.Value{}
	if m.arrayObject == nil {
		return
	}
	v := reflect.ValueOf(m.arrayObject)
	if v.IsZero() {
		return
	}
	n := v.Len()
	if n == 0 {
		return
	}
	for i := 0; i < n; i++ {
		field := v.Index(i)
		if field.Kind() == reflect.Ptr {
			if field.IsNil() {
				continue
			}
		}
		addr := field.Pointer()
		mp[addr] = field
	}
	return
}

/**
 * @description: 过虑满足条件的数据
 * @param {*Query} m
 * @return {*}
 */
func (m *Table) filter(
	isAnd bool, //是否是and运算
	key string,
	value interface{},
	intFunc func(a, b int64) bool,
	floatFunc func(a, b float64) bool,
	stringFunc func(a, b string) bool,
) (arr *Table, err error) {
	if !isAnd {
		return m.orFilter(key, value, intFunc, floatFunc, stringFunc)
	}
	arr = new(Table)
	arr.key = m.key
	if key == "" {
		err = errors.New("缺少列名")
		return
	}
	arr.parent = m.arrayObject
	v := reflect.ValueOf(m.arrayObject)
	n, valueType, ids, err := m.checkPreconditions(v, key)
	if err != nil {
		return
	}
	floatValue := 0.0
	intValue := int64(0)
	stringValue := ""

	//如果值类型是数字，则参数类型必须是数字
	if valueType != easy.TypeString {
		paramType := easy.GetType(value)
		if paramType == easy.TypeNull || paramType == easy.TypeString {
			err = errors.New("参数类型和值类型不一致")
			return
		}
	}

	switch valueType {
	case easy.TypeFloat:
		floatValue, _ = easy.GetFloat64(value)
	case easy.TypeInt:
		intValue, _ = easy.GetInt64(value)
	case easy.TypeString:
		stringValue = value.(string)
	default:
		err = errors.New("不支持的数据类型")
		return
	}

	vals := reflect.MakeSlice(v.Type(), n, n)
	count := 0
	for i := 0; i < n; i++ {
		field := v.Index(i)
		if field.Kind() == reflect.Ptr {
			if field.IsNil() {
				continue
			}
		}
		elem := reflect.Indirect(field)
		if elem.IsValid() && !elem.CanInterface() {
			continue
		}
		//ie := elem.Interface()
		//log.Println(ie)
		if !elem.IsValid() {
			continue
		}
		elem, err = FieldByIndex(elem, ids)
		if err != nil {
			continue
		}
		if !elem.CanInterface() {
			continue
		}
		switch valueType {
		case easy.TypeFloat:
			fval, err := easy.GetFloat64(elem.Interface())
			if err != nil {
				continue
			}
			if floatFunc(fval, floatValue) {
				vals.Index(count).Set(field)
			} else {
				continue
			}
		case easy.TypeInt:
			ival, err := easy.GetInt64(elem.Interface())
			if err != nil {
				continue
			}
			if intFunc(ival, intValue) {
				vals.Index(count).Set(field)
				//log.Printf("%v", field.Type().String())
			} else {
				continue
			}
		case easy.TypeString:
			if stringFunc(elem.String(), stringValue) {
				vals.Index(count).Set(field)
			} else {
				continue
			}
		default:
			continue
		}
		count++
	}

	if count > 0 {
		x := reflect.New(v.Type())
		x.Elem().Set(vals)
		x.Elem().SetLen(count)
		arr.arrayObject = x.Elem().Interface()
	} else {
		err = errNoOkData
	}
	return arr, err
}

//
/**
 * @description: 检查field 是否可用
 * @param {reflect.Value} v
 * @return {*}
 */
func (m *Table) checkField(field reflect.Value, ids []int) (elem reflect.Value, ok bool) {
	if field.Kind() == reflect.Ptr {
		if field.IsNil() {
			return field, false
		}
	}
	elem = reflect.Indirect(field)
	// if elem.IsValid() && !elem.CanInterface() {
	// 	return field, false
	// }
	if !elem.IsValid() {
		return field, false
	}
	elem, err := FieldByIndex(elem, ids)
	if err != nil {
		ok = false
		return
	}
	if !elem.CanInterface() {
		return field, false
	}
	return elem, true
}

/**
 * @description: 前置条件的验证
 * @param {reflect.Value} v
 * @param {string} key
 * @param {bool} setError
 * @return {*}
 */
func (m *Table) checkPreconditions(v reflect.Value, key string) (size int, valueType byte, ids []int, err error) {
	ids, ok := m.key[key]
	if !ok {
		err = errors.New("没有此列名" + key)
		return 0, easy.TypeNull, nil, err
	}
	size = v.Len()
	if size == 0 {
		return 0, easy.TypeNull, nil, errNoData
	}

	//获取数组内的数据类型
	typ := v.Type()
	typ = typ.Elem()
	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
	}

	typ = typ.FieldByIndex(ids).Type

	//log.Println(typ.Name(), "==>", typ.Kind())

	valueType = easy.GetReflectType(typ)
	if valueType == easy.TypeNull {
		err = errors.New("值类型是NULL")
		return 0, easy.TypeNull, nil, err
	}
	return
}

/**
 * @description: 前置条件的验证
 * @param {reflect.Value} v
 * @param {string} key
 * @param {bool} setError
 * @return {*}
 */
func (m *Table) checkPreconditionsOr(v reflect.Value, key string) (size int, valueType byte, ids []int, err error) {
	ids, ok := m.key[key]
	if !ok {
		err = errors.New("没有此列名" + key)
		return 0, easy.TypeNull, nil, err
	}

	if !v.IsValid() {
		return 0, easy.TypeNull, nil, errNoData
	}
	size = v.Len()
	if size == 0 {
		return 0, easy.TypeNull, nil, errNoData
	}

	//获取数组内的数据类型
	typ := v.Type()
	typ = typ.Elem()
	if typ.Kind() == reflect.Ptr {
		typ = typ.Elem()
	}

	typ = typ.FieldByIndex(ids).Type

	//log.Println(typ.Name(), "==>", typ.Kind())

	valueType = easy.GetReflectType(typ)
	if valueType == easy.TypeNull {
		err = errors.New("值类型是NULL")
		return 0, easy.TypeNull, nil, err
	}
	return
}
